package com.czb.czbmybatis.sqlsession;

import com.czb.czbmybatis.config.Function;
import com.czb.czbmybatis.config.MapperBean;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;

/**
 * @author: 陈正彬
 * 读取xml建立连接
 */
public class CzbConfiguration {
    //属性，类的加载器
    private static ClassLoader loader = ClassLoader.getSystemClassLoader();
    //读取xml信息 ，并处理
    public Connection build(String resource) {
        Connection connection = null;
        try {
            //加载配置 czb_mybatis.xml ,获取对应的InputStream
            InputStream stream = loader.getResourceAsStream(resource);
            //解析czb_mybatis.xml，dom4j
            SAXReader reader = new SAXReader();
            Document document = reader.read(stream);
            //获取czb_mybatis.xml的根元素 <database>
            Element root = document.getRootElement();
            System.out.println("root = " + root);
            //解析root元素，返回Connection,调用方法
            connection = evalDataSource(root);
        } catch (DocumentException e) {
            throw new RuntimeException(e);
        }
        return connection;

    }

    //编写方法解析czb_mybatis.xml 信息，返回Connection
    private Connection evalDataSource(Element node) {
        if (!("database".equals(node.getName()))) {
            throw new RuntimeException("root 节点不是<database>");
        }
        String driveClassName = null;
        String url = null;
        String username = null;
        String password = null;
        
        //遍历node下的子节点
        for (Object item : node.elements("property")) {
            Element i = (Element) item; //i 对应property的节点
            String name = i.attributeValue("name");
            String value = i.attributeValue("value");
            if (name == null || value == null) {
                throw new RuntimeException("property 节点没有设置name或者value属性");
            }
            switch (name) {
                case "url":
                    url = value;
                    break;
                case "username":
                    username = value;
                    break;
                case "password":
                    password = value;
                    break;
                case "driverClassName":
                    driveClassName = value;
                    break;
                default:throw new RuntimeException("属性名没有匹配到");
            }

        }
        Connection connection = null;
        try {
            Class.forName(driveClassName);
            connection = DriverManager.getConnection(url,username,password);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        return connection;
    }
    //读取XXXMapper.xml ,能够创建MapperBean对象
    //path就是要读取的xml的路径 是从类的加载路径计算的
    //如果XXXMapper.xml 是放在resources目录下，直接传入xml文件名即可
    public MapperBean readMapper(String path) {
        MapperBean mapperBean = new MapperBean();
        try {
            //获取xml文件对应的InPutStream
            InputStream stream = loader.getResourceAsStream(path);
            SAXReader saxReader = new SAXReader();
            //获取xml文件对应的document
            Document document = saxReader.read(stream);
            //获取xml文件的根元素
            Element root = document.getRootElement();
            //trim() 防止空格
            String namespace = root.attributeValue("namespace").trim();
            mapperBean.setInterfaceName(namespace);

            //得到root的迭代器-遍历他的子节点,生成Function
            Iterator iterator = root.elementIterator();
            ArrayList<Function> functions = new ArrayList<>();
            //遍历子元素
            while (iterator.hasNext()) {
                //取出子元素
                Element e = (Element) iterator.next();
                Function function = new Function();
                String sqlType = e.getName().trim();
                String funcName = e.attributeValue("id").trim();
                String resultType = e.attributeValue("resultType").trim();
                String sql = e.getText().trim();

                //封装
                function.setSql(sql);
                function.setFunName(funcName);
                function.setSqlType(sqlType);
                //因为private Object resultType , 是resultType实例
                //使用反射生成一个 对象
                Object instance = Class.forName(resultType).newInstance();
                function.setResultType(instance);


                functions.add(function);
            }
            //循环结束后，将function的list设置
            mapperBean.setFunctions(functions);

        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        return mapperBean;
    }

}
